﻿using System;
using System.IO;
using System.Drawing;
using WiMo.Games.Drawables;
using WiMo.Games.Premium.GDIDisplay.DirectDraw;
using WiMo.Games.Premium.GDIDisplay.ImageAPI;

namespace WiMo.Games.Premium.GDIDisplay.Drawables
{
    internal class WiMoImage : IWiMoImage
    {
        private WiMoImage() { }
        private IContentManager _contentManager;

        public static WiMoImage Create(Size size)
        {
            var newImage = new WiMoImage { 
                Size = size, 
                BitmapImage = new Bitmap(size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb) 
            };

            return newImage;
        }

        public static WiMoImage Create(Bitmap bitmap)
        {
            return new WiMoImage
            {
                BitmapImage = bitmap,
                Size = new Size(bitmap.Width, bitmap.Height),
                Transparency = 0xFF
            };
        }

        public static WiMoImage Create(IContentManager contentManager, string name)
        {
            var newImage = new WiMoImage();
            newImage._contentManager = contentManager;
            newImage.LoadImagingImage(name);

            return newImage;
        }        

        public void LoadImagingImage(string name)
        {
            ImagingImage = LoadImagingImage(name, "png");

            if (ImagingImage == null)
                ImagingImage = LoadImagingImage(name, "bmp");      
            
        }

        private IImage LoadImagingImage(string name, string extension)
        {
            var assembly = _contentManager.Engine.Game.GetType().Assembly;
            var path = String.Format("{0}.{1}._{2}.{3}.{4}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), _contentManager.ContentLocation, _contentManager.Engine.Display.DPI, name.Replace("/", "."), extension);
            var stream = assembly.GetManifestResourceStream(path);
            if (stream == null)
            {
                path = String.Format("{0}.{1}.{2}.{3}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), _contentManager.ContentLocation, name.Replace("/", "."), extension);
                stream = assembly.GetManifestResourceStream(path);

                if (stream == null)
                    return null;
            }

            IImage image;
            var imageData = new byte[stream.Length];
            stream.Read(imageData, 0, (int)stream.Length);
            IImagingFactory factory = ImagingFactory.GetImaging();
            factory.CreateImageFromBuffer(imageData, (uint)imageData.Length, BufferDisposalFlag.BufferDisposalFlagNone, out image);
            stream.Dispose();

            //Need to read in to initialize.
            ImageInfo imageInfo;
            image.GetImageInfo(out imageInfo);

            return image;
        }

        public static WiMoImage CreateForText(IWiMoGraphics graphics, ISpriteText text)
        {
            var textSize = graphics.MeasureString(text.Text, text.Font.FontInformation as Font);
            //Scaling for font size happens automatically so if we want to set the auto size
            //for the text, we need to divided by current scale.
            if (text.Size == Size.Zero)
                text.UnscaledSize = new Size(textSize.Width / text.Scale.X, textSize.Height / text.Scale.Y);

            var newImage = WiMoImage.Create(text.Size);            

            if (text.BackgroundColor == Color.Transparent)
                text.ColorKey = text.ForeColor.GetInverted();
            else
                text.ColorKey = Color.Transparent;

            var bgBrush = new SolidBrush(text.BackgroundColor == Color.Transparent ? text.ForeColor.GetInverted().ToDrawingColor() : text.BackgroundColor.ToDrawingColor());
            using (var bmGraphics = Graphics.FromImage(newImage.BitmapImage))
            {
                bmGraphics.FillRectangle(bgBrush, 0, 0, text.Size.Width, text.Size.Height);

                var left = (text.Origin == Origin.TopLeft) ? 0 : (text.Size.Width - textSize.Width) / 2;
                var top = (text.Origin == Origin.TopLeft) ? 0 : (text.Size.Height - textSize.Height) / 2;

                using (var sb = new SolidBrush(text.ForeColor.ToDrawingColor()))
                {
                    bmGraphics.DrawString(text.Text, text.Font.FontInformation as Font, sb, left, top);
                }
            }
            return newImage;
        }

        public void CreateImagingImage()
        {
            using (var memoryStream = new MemoryStream())
            {
                BitmapImage.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
                
                IImage image;
                ImagingFactory.GetImaging().CreateImageFromStream(new ImagingStream(memoryStream), out image);

                ImageInfo info;
                image.GetImageInfo(out info);
                System.Diagnostics.Debug.WriteLine("Size -> " + info.Width + "," + info.Height + " - " + info.pixelFormat);

                ImagingImage = image;

                IBitmapImage ibmp;
                ImagingFactory.GetImaging().CreateBitmapFromImage(image, info.Width, info.Height, PixelFormatID.PixelFormat32bppRGB, InterpolationHint.InterpolationHintDefault, out ibmp);
                ImagingBitmap = ibmp;
            }
        }

        static uint MAKERGB(int r, int g, int b)
        {
            return ((uint)(b & 255)) | ((uint)((r & 255) << 8)) | ((uint)((g & 255) << 16));
        }

        public BITMAPINFO BitmapInfo
        {
            get
            {
                var bpp = 8;
                var bmi = new BITMAPINFO();
                bmi.biSize = 40;
                bmi.biWidth = Size.Width;
                bmi.biHeight = Size.Height;
                bmi.biPlanes = 1;
                bmi.biBitCount = 16;
                bmi.biCompression = 0;
                bmi.biSizeImage = (uint)(Size.Width * Size.Height);
                bmi.biBitCount = (short)bpp;
                               
                bmi.bmiColors = new uint[256];
                bmi.bmiColors[0] = 0xF800;
                bmi.bmiColors[1] = 0x07e0;
                bmi.bmiColors[2] = 0x001f;
                //for (var i = 0; i < 8; ++i )
                //    bmi.bmiColors[i] = MAKERGB(i, i, i);

                return bmi;
            }
        }

        public void CreateSurfaceImage(DirectDrawGraphics dd)
        {
            SurfaceImage = dd.CreateSurface(Size.Width, Size.Height);
            if(ImagingImage != null)
                SurfaceImage.LoadImage(ImagingImage);
            else
                SurfaceImage.LoadImage(BitmapImage);

        }

        public static WiMoImage CreateForRect(ISpriteShape rect)
        {
            var newImage = WiMoImage.Create(rect.Size);
            newImage.ColorKey = rect.ColorKey;
            newImage.Transparency = rect.FillColor.A;

            using (var gr = Graphics.FromImage(newImage.BitmapImage as Bitmap))
            {
                if (rect.BorderRadius > 0)
                {
                    var scaledRadius = new System.Drawing.Size((int)(rect.BorderRadius * rect.Scale.X), (int)(rect.BorderRadius * rect.Scale.Y));
                    gr.DrawRectangle(rect.Size, rect.BorderColor, rect.FillColor, scaledRadius, rect.FillColor.A);

                    var transparentColor = newImage.BitmapImage.GetPixel(0, 0);
                    rect.ColorKey = new Color(transparentColor.R, transparentColor.G, transparentColor.B);
                    newImage.ColorKey = rect.ColorKey;
                }
                else
                {                    
                    if (rect.FillColor != Color.Transparent)
                        using (var sb = new SolidBrush(rect.FillColor.ToDrawingColor()))
                        {
                            gr.FillRectangle(sb, 0, 0, rect.Size.Width, rect.Size.Height);
                        }

                    if (rect.BorderColor != Color.Transparent)
                        using (var pen = new Pen(rect.BorderColor.ToDrawingColor(), Convert.ToSingle(rect.BorderWidth)))
                        {
                            gr.DrawRectangle(pen, 0, 0, rect.Size.Width, rect.Size.Height);
                        }
                }
            }

            return newImage;
        }

        internal IBitmapImage ImagingBitmap { get; set; }
        internal IImage ImagingImage { get; set; }
        internal Bitmap BitmapImage { get; set; }
        internal Surface SurfaceImage { get; set; }

        public Size Size { get; set; }
        public Color ColorKey { get; set; }
        public RenderStrategy RenderStrategy { get; set; }
        public byte Transparency { get; set; }
        public string Name { get; set; }
    }
}
